Skip to content

[pull] master from supabase:master - #1132

Merged
pull[bot] merged 6 commits into
code:masterfrom
supabase:master
Aug 3, 2026
Merged

[pull] master from supabase:master#1132
pull[bot] merged 6 commits into
code:masterfrom
supabase:master

Conversation

@pull

@pull pull Bot commented Aug 3, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

dnywh and others added 6 commits August 3, 2026 09:43
## What kind of change does this PR introduce?

Bug fix and design-system update.

## What is the current behavior?

API authorisation and AWS Marketplace action failures use transient
toasts. The inline action-error treatment introduced for organisation
invitations is implemented locally.

## What is the new behavior?

Action failures remain visible below their actions and clear on retry or
organisation change.

This PR adds a shared `InterstitialActionError` component, updates the
connect-interstitial guidance and demo to use it, and retroactively
applies it to `OrganizationInvite`.

Mutation errors are read directly from their mutation hooks rather than
copied into component state.

| Before | After |
| --- | --- |
| <img width="1024" height="759" alt="Authorize API Access Supabase"
src="https://github.com/user-attachments/assets/9520aff3-496d-44b1-b5b5-02b331872e32"
/> | <img width="1024" height="759" alt="Authorize API Access Supabase"
src="https://github.com/user-attachments/assets/2d09e337-573a-45b5-80ac-7c546ed1401d"
/> |
| <img width="1024" height="759" alt="Link AWS Marketplace Supabase"
src="https://github.com/user-attachments/assets/bb1a4581-0399-432a-8037-d84ab15ecc4b"
/> | <img width="1024" height="759" alt="Link AWS Marketplace Supabase"
src="https://github.com/user-attachments/assets/f9d43cd9-c661-42ed-91c0-e45ccb9c19f5"
/> |

_Note since taking that AWS screenshot: the error message now replaces
the prior footer text. I.e. “Learn more about billing through AWS.” is
now gone when an error message is present._

## To test

### AWS Marketplace

For a visual check with local Studio running:

1. In
`apps/studio/components/interfaces/Organization/CloudMarketplace/AwsMarketplaceOnboarding.tsx`,
immediately before `if (!buyerId)`, temporarily add:
   ```tsx
   return (
     <AwsMarketplaceInterstitial>
       <div className="flex flex-col gap-5">
         <InterstitialAccountRow displayName="reviewer@example.com" />
         <OrganizationSelector
           organizations={[
             {
               name: 'Example Organization',
               slug: 'example-organization',
               plan: { id: 'pro', name: 'Pro' },
             } as Organization,
           ]}
           selectedSlug="example-organization"
           disabled
           onSelect={() => undefined}
         />
         <div className="flex flex-col gap-5">
           <div className="flex flex-col gap-2">
             <Button variant="primary" block>
               Link organization
             </Button>
<InterstitialActionError error="Failed to link organization: Test error"
/>
           </div>
<p className="text-center text-xs text-foreground-lighter text-balance">
<InlineLink href={`${DOCS_URL}/guides/platform/aws-marketplace`}>
               Learn more
             </InlineLink>{' '}
             about billing through AWS.
           </p>
         </div>
       </div>
     </AwsMarketplaceInterstitial>
   )
   ```
2. Open `http://localhost:8082/aws-marketplace-onboarding?buyer_id=test`
while signed in.
3. Confirm the error appears below **Link organization** with a divider.

Remove the temporary return before committing anything.

### API authorization

For a visual check with local Studio running:

1. In
`apps/studio/components/interfaces/ApiAuthorization/ApiAuthorization.Valid.tsx`,
immediately before `if (isLoading)`, temporarily add:
   ```tsx
   return (
     <ApiAuthorizationMainView
       approvalState="indeterminate"
       form={form}
       requester={{
         name: 'Test App',
         website: 'https://example.com',
         icon: null,
         domain: 'example.com',
         scopes: [],
         expires_at: '2099-01-01T00:00:00.000Z',
         approved_at: null,
         registration_type: 'static',
       }}
       organizations={{
         _tag: 'success',
         organizations: [
{ name: 'Example Organization', slug: 'example-organization' } as
Organization,
         ],
       }}
       requestedOrganizationSlug={undefined}
       actionError="Failed to authorize request: Test error"
       onOrganizationChange={() => undefined}
       onApprove={() => undefined}
       onDecline={() => undefined}
     />
   )
   ```
2. Open `http://localhost:8082/authorize?auth_id=test` while signed in.
3. Confirm the error appears below the authorisation actions with a
divider.

Remove the temporary return before committing anything.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added consistent inline error messaging for authorization,
organization invitations, and AWS Marketplace onboarding.
* Error messages now appear within the relevant interstitial and replace
supporting footer content until resolved.
  * Retry and action buttons remain available after failed operations.
* **Bug Fixes**
* AWS Marketplace linking failures no longer trigger toast
notifications.
  * Billing guidance is hidden while an onboarding error is displayed.
* **Tests**
* Added coverage for authorization, cancellation, and AWS Marketplace
failure states.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
## What kind of change does this PR introduce?

Feature + docs. Stacked on #48161 (logo contract /
[DEPR-604](https://linear.app/supabase/issue/DEPR-604/define-connect-logo-asset-and-variant-contract)).

## What is the current behavior?

After #48161, curated logos only resolve from allowlisted `redirect_uri`
hosts. A requester can still present a trusted partner **name** (e.g.
Claude) while redirecting to an unrelated remote host; the UI shows
Supabase alone but does not call out the mismatch.

## What is the new behavior?

- Shows a caution admonition when the requester name looks like a
trusted partner (Claude, Cursor, ChatGPT/OpenAI, Perplexity) but
`redirect_uri` is a **remote** host outside that partner's allowlist.
- Skips localhost / loopback redirects for the caution (common for local
MCP clients); those still get curated logos when the name matches a
trusted partner.
- Highlights the footer redirect URL in warning colour when the caution
is shown.
- Documents the behaviour in the Connect interstitials pattern.

### To test

Real MCP clients (Claude, Cursor, etc.) only send users to
**production** `/authorize`, so you cannot drive a local or preview
Studio build from those tools. Use a Network override instead:

1. Start Studio and sign in (`pnpm dev:studio`, or use the [Vercel
preview](https://studio-staging-git-danny-oauth-impersonation-warning-supabase.vercel.app/)).
2. Open `/dashboard/authorize?auth_id=foo` (any `auth_id` is fine; the
real response may 404) ([Vercel
preview](https://studio-staging-git-danny-oauth-impersonation-warning-supabase.vercel.app/dashboard/authorize?auth_id=foo)).
3. DevTools → **Network** → find `GET
…/platform/oauth/authorizations/foo` (or whatever id you used).
4. Right-click → **Override content** (enable Local Overrides / pick a
folder if prompted).
5. Paste one of the payloads below (status **200**), save, then reload
the authorize page.
6. Keep `expires_at` in the future so the request does not look expired.

#### Impersonation caution (trusted name + remote non-allowlisted
redirect)

Expect:

- Supabase alone (no curated Claude mark)
- Caution: “Redirect does not match this app name”
- Footer redirect URL in warning colour

```json
{
  "name": "Claude",
  "website": "https://claude.ai",
  "icon": null,
  "domain": "claude.ai",
  "redirect_uri": "https://evil.com/callback",
  "expires_at": "2099-01-01T00:00:00.000Z",
  "scopes": ["organizations:read", "projects:read"],
  "approved_at": null,
  "registration_type": "dynamic"
}
```

| Preview |
| --- |
| <img width="764" height="958" alt="Authorize Claude Supabase"
src="https://github.com/user-attachments/assets/e6eee016-5710-41ba-9925-87511e009e22"
/> |

#### Localhost MCP: no caution

Expect curated Claude + Supabase pair (name match + loopback), **no**
caution, normal footer colour. Local MCP clients often use loopback
redirects.

```json
{
  "name": "Claude",
  "website": "https://claude.ai",
  "icon": null,
  "domain": "claude.ai",
  "redirect_uri": "http://127.0.0.1:42813/callback",
  "expires_at": "2099-01-01T00:00:00.000Z",
  "scopes": ["organizations:read", "projects:read"],
  "approved_at": null,
  "registration_type": "dynamic"
}
```

| Preview |
| --- |
| <img width="764" height="958" alt="Authorize Claude Supabase"
src="https://github.com/user-attachments/assets/79f36865-3c8e-43e5-9490-24288efc74aa"
/> |

#### Legitimate curated partner: no caution

Expect curated Cursor + Supabase pair, no admonition, normal footer
colour.

```json
{
  "name": "Cursor",
  "website": "https://cursor.com",
  "icon": null,
  "domain": "cursor.com",
  "redirect_uri": "https://cursor.com/callback",
  "expires_at": "2099-01-01T00:00:00.000Z",
  "scopes": ["organizations:read", "projects:read"],
  "approved_at": null,
  "registration_type": "dynamic"
}
```

| Preview |
| --- |
| <img width="764" height="958" alt="56164"
src="https://github.com/user-attachments/assets/412333a3-a74f-42eb-9f63-d56b6a26bf91"
/> |

#### Unrelated name + remote redirect: no caution

Expect Supabase alone (no icon), no admonition.

```json
{
  "name": "Acme Tools",
  "website": "https://evil.com",
  "icon": null,
  "domain": "evil.com",
  "redirect_uri": "https://evil.com/callback",
  "expires_at": "2099-01-01T00:00:00.000Z",
  "scopes": ["organizations:read", "projects:read"],
  "approved_at": null,
  "registration_type": "dynamic"
}
```

| Preview |
| --- |
| <img width="764" height="958" alt="Authorize Acme Tools Supabase"
src="https://github.com/user-attachments/assets/dab24817-5c26-4aa1-a447-796c4af5868b"
/> |

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Summary by CodeRabbit

- **New Features**
- Added an OAuth caution when a requester name matches a known partner
but uses an unapproved remote redirect host.
- Improved trusted partner logo selection for localhost/loopback
redirects while preserving safe fallbacks for untrusted redirects.

- **Documentation**
- Updated Connect interstitial guidance for redirect mismatches and
localhost/loopback behavior.

- **Tests**
- Expanded coverage for caution visibility, messaging, localhost logo
pairing, and trusted redirect scenarios.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
…8222)

## What kind of change does this PR introduce?

Accessibility / UX fix
([DEPR-630](https://linear.app/supabase/issue/DEPR-630)).

## What is the current behavior?

In Storage **As columns** view, keyboard select is unclear: the checkbox
stays hidden until hover, so Tab/Space selection is hard to see. The row
actions (three dots) menu also shows a browser default blue outline on
Tab.

## What is the new behavior?

Same icon/checkbox swap as list/hover, but also on keyboard focus:
- Checkbox replaces the icon on hover, `:focus-within`, and when
selected (no layout shift)
- Checkbox becomes visible when focused via keyboard (without needing
hover)
- Row gets an inset outline while the checkbox is focused
- Folders have no checkbox (non-focusable spacer only)
- Row actions trigger uses `focus-ring` instead of the browser blue
outline

| Before | After |
| --- | --- |
| <img width="1046" height="362" alt="CleanShot 2026-07-31 at 14 37
47@2x"
src="https://github.com/user-attachments/assets/9b827627-17e6-49a6-87a3-1253b4cef1da"
/> | <img width="1046" height="390" alt="CleanShot 2026-07-31 at 14 37
13@2x"
src="https://github.com/user-attachments/assets/2fd2b426-a8e2-4fda-b1ba-4df728b7b2f1"
/> |
| _Checkbox focussed but not visually shown_ | _Checkbox focussed and
visually shown_ |

## To test

1. Open the **Studio preview** for this PR.
2. Go to **Storage → Files** → open a bucket with several files.
3. Set view to **As columns**.
4. Tab until a **file** checkbox is focused.

**Expect:**
- Icon is replaced by the checkbox (same slot; neighbouring row icons
should not look shifted)
- Checkbox visible without hovering
- Row shows an inset outline

5. Press **Space** to select. Checkbox stays in the icon slot; selection
background applies.
6. Hover another file. Same icon to checkbox swap as before.
7. Tab to the three-dot actions control on a row. Expect the shared
focus ring (not a blue browser outline); the menu icon should become
visible.
8. Folders: no checkbox in the tab order; click icon/name still opens
the folder.
9. Smoke **As list**. Same swap behaviour.

## Additional context

From Kemal's DEPR-621 review.
…forms (#48522)

## What kind of change does this PR introduce?

Bug fix (dirty form dismissal for Replication destination sheets), plus
small docs/skill updates so agents pick up the existing modality
pattern.

## What is the current behavior?

Closing the Add/Edit destination sheet (Cancel, Escape, or backdrop)
discards in-progress form state with no confirm. Same for the nested
Create publication sheet.

## What is the new behavior?

Dirty closes go through `useConfirmOnClose` +
`DiscardChangesConfirmationDialog`, matching other Studio sheets.
Successful submit still closes without prompting.

Also: skills + `forms.mdx` now point at Modality “Dirty form dismissal”.

| After |
| --- |
| <img width="1024" height="759" alt="Replication Database Chisel
Toolshed Supabase"
src="https://github.com/user-attachments/assets/6f568a2a-c76b-442a-b592-d638bb36adc4"
/> |

### How to test

1. Studio → Database → Replication → **Add destination** (any pipelines
type with access).
2. Change a field so the form is dirty.
3. Try Cancel, Escape, and backdrop click → discard dialog appears;
**Keep editing** stays open; **Discard changes** closes.
4. Submit successfully with a valid config → sheet closes with no
discard dialog.
5. Repeat for **Edit destination** from a destination row menu.
6. Optional: Add destination → create a new publication from the
publication picker → dirty that nested sheet and dismiss the same way.
7. Optional: Add destination → Read Replica → change region → dismiss →
discard dialog; deploy still closes without prompting.

## Additional context

Sheet owns the close guard; forms report dirty via a ref because RHF
lives in the child. Nested `NewPublicationPanel` wires the guard
locally.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added unsaved-changes tracking to replication destination and
publication forms.
- Added confirmation prompts before closing forms with unsaved changes
via Cancel, Escape, or backdrop dismissal.
- Forms now reset appropriately after successful submission or confirmed
dismissal.

- **Documentation**
- Updated form and UI pattern guidance to document dirty-form dismissal
behavior for sheets and dialogs.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
## What kind of change does this PR introduce?

Bug fix. Resolves DEPR-539.

## What is the current behavior?

When a focused child unmounts, Radix can move focus to the Sheet wrapper
and break the expected tab order. Several callsites suppress the
wrapper's tabindex individually.

## What is the new behavior?

Sheet still focuses its first interactive child when opened, but the
wrapper itself is no longer focusable by default. Callers can opt in
with an explicit `tabIndex` when needed.

## Additional context

### Testing

Compare this Studio experience on both this branch and `master`:

1. Open any project with an Edge Function.
2. Go to **Edge Functions**, open the function, then click **Test**.
3. Under **Headers**, click **Add Headers**. Click the first header key
input, then Tab slowly through the header inputs and remove buttons.

On `master`, focus can jump to the whole Sheet. On this branch, focus
stays on the controls in order.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
  * Improved keyboard focus behavior across sheets and panels.
* Sheets now focus the first available interactive element when opened,
without adding unnecessary focus targets.
* Preserved support for programmatic focus and prevented focus from
unexpectedly moving to the sheet when focused content is removed.
* Updated authentication, integrations, connection, logging, storage,
and other sheet interfaces consistently.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
…48517)

## What kind of change does this PR introduce?

Docs update / follow-up to #48379.

## What is the current behavior?

`/guides/resources` and `/guides/getting-started` hand-roll `GlassPanel`
grids in MDX. They look like ContentListings cards after the chrome PR,
but they do not use the shared data files, so they miss PostHog
`docs_content_listing_clicked` telemetry and the CONTRIBUTING
contribution path.

## What is the new behavior?

Those pages use `<ContentListings id="…" />` backed by
`resources.data.ts` and `getting-started.data.ts`, same pattern as
storage.

- Section-level `$Show` wrappers stay for framework / web / mobile
blocks
- Nimbus stays a `$Partial` behind `$Show`
- New optional per-item `feature` field gates SDK links (e.g. Flutter /
Swift / Kotlin) without splitting whole sections
- CONTRIBUTING notes when to use `feature` vs a partial-level `$Show`

## To test

Compare the following against `master`:

-
[Resources](https://docs-git-dnywh-docs-content-listings-resources-239158-supabase.vercel.app/docs/guides/resources):
overview, migrate, and postgres grids; icons in light/dark
- [Getting
started](https://docs-git-dnywh-docs-content-listings-resources-239158-supabase.vercel.app/docs/guides/getting-started):
overview, use cases, framework quickstarts, web demos, mobile tutorials;
nimbus partial when enabled
- Click a card and confirm `docs_content_listing_clicked` fires with the
expected `listingId`

Everything should look and feel the same. It’s just that we’re using
`ContentListings` instead of `GlassPanel` grids.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added centralized Getting Started and Resources content listings,
including quickstarts, demos, tutorials, migration guides, and Postgres
resources.
- Added feature-based visibility controls for individual content listing
items.

- **Improvements**
- Disabled content is now automatically hidden from documentation pages
and generated Markdown.
  - Pages and sections with no available content are omitted entirely.
  - External documentation links are more secure.
- Updated contribution guidance with instructions and examples for
feature flags.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@pull pull Bot locked and limited conversation to collaborators Aug 3, 2026
@pull pull Bot added the ⤵️ pull label Aug 3, 2026
@pull
pull Bot merged commit c0f1ef5 into code:master Aug 3, 2026
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Aug 3, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

⤵️ pull documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant